/**
 * 
 */
package com.boronstream.istar.http;

import java.lang.ref.WeakReference;

import org.apache.http.HttpStatus;

import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.util.Log;

import com.boronstream.istar.PlayApplication;
import com.boronstream.istar.http.PlayRequestListener.ResultType;
import com.boronstream.istar.utils.MiscUtils;

/**
 * @author Stream
 * 
 */
public class PlayNetworkCenter {

	private static final String TAG = PlayNetworkCenter.class.getSimpleName();
	public static final int CALLBACK_CODE = 0x1111;

	private static PlayNetworkCenter playNetworkCenter;

	private PlayNetworkCenter() {

	}

	public static PlayNetworkCenter getInstance() {
		if (playNetworkCenter == null) {
			playNetworkCenter = new PlayNetworkCenter();
		}
		return playNetworkCenter;
	}

	/**
	 * 
	 * @param request
	 * @param listener
	 * @return A 'NetworkTask' will be returned, and you can control the task as
	 *         you like.For example, <code>network.cancel(true);</code><br>
	 *         This can cancel the current request,and of course, the result
	 *         will not be called back to the main thread.
	 */
	public NetworkTask startRequest(
			final PlayRequest<? extends PlayResponse> request,
			final PlayRequestListener listener) {
		 NetworkTask task = new NetworkTask(listener, null);
		 task.execute(request);
		return task;
	}

	/**
	 * callback data will returned in msg.what = {@link #CALLBACK_CODE}
	 * 
	 * @param request
	 * @param listener
	 * @return A 'NetworkTask' will be returned, and you can control the task as
	 *         you like.For example, <code>network.cancel(true);</code><br>
	 *         This can cancel the current request,and of course, the result
	 *         will not be called back to the main thread.
	 */
	public NetworkTask startRequest(
			PlayRequest<? extends PlayResponse> request, Handler callbackHandler) {

		// TODO:Check net work status,if not reachable ,callback

		if (callbackHandler == null) {
			return null;
		}

		NetworkTask task = new NetworkTask(null, callbackHandler);
		task.execute(request);
		return task;
	}

	private class NetworkTask extends
			AsyncTask<PlayRequest<? extends PlayResponse>, Void, PlayResponse> {
		private final WeakReference<PlayRequestListener> listenerReference;
		private final WeakReference<Handler> handlerReference;

		public NetworkTask(PlayRequestListener listener, Handler handler) {
			this.listenerReference = new WeakReference<PlayRequestListener>(
					listener);
			this.handlerReference = new WeakReference<Handler>(handler);
		}

		@Override
		protected PlayResponse doInBackground(
				PlayRequest<? extends PlayResponse>... params) {
			// Log.d(TAG,"DoInBackground..."+params[0]);
			return new DefaultPlayClient().execute(params[0]);
		}

		@Override
		protected void onCancelled() {
			// Log.w(TAG, "oncalled");
			super.onCancelled();
		}

		// @Override
		// protected void onCancelled(PlayResponse result) {
		// Log.w(TAG, "oncalled:"+result);
		// super.onCancelled(result);
		// }

		/**
		 * If current task has not been canceled and the WeakReference of
		 * <code>{@link #listenerReference}</code> is not null,or the
		 * WeakReference of <code>{@link #handlerReference}</code>,the result
		 * will be returned to {@link #listenerReference} or
		 * {@link #handlerReference}
		 */
		@Override
		protected void onPostExecute(PlayResponse response) {

			Log.d(TAG, "onPostExecute response == " + response);

			/**
			 * Method 1.
			 */
			if (!isCancelled() && this.listenerReference != null) {
				PlayRequestListener listener = listenerReference.get();

				Log.d(TAG, "onPostExecute  listenerReference == "
						+ listenerReference);
				Log.d(TAG, "onPostExecute  listener == " + listener);

				if (listener != null) {
					ResultType resultType = ResultType.UNKNOWN_ERROR;
					if (response == null) {
						resultType = ResultType.SERVER_ERROR;
					} else if (response.getStatusCode() == HttpStatus.SC_OK
							|| response.getStatusCode() == HttpStatus.SC_ACCEPTED
							|| response.getStatusCode() == HttpStatus.SC_CREATED
							|| response.getStatusCode() == HttpStatus.SC_PARTIAL_CONTENT) {
						resultType = ResultType.SUCCESS;
					} else if (response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
						resultType = ResultType.NO_PERMISSION;
					} else if (!MiscUtils.checkNet(PlayApplication.context)) {
						resultType = ResultType.NO_NETWORK;
					} else if (response.getStatusCode() == HttpStatus.SC_REQUEST_TIMEOUT) {
						resultType = ResultType.TIME_OUT;
					} else if (response.getStatusCode() == HttpStatus.SC_FORBIDDEN
							|| response.getStatusCode() == HttpStatus.SC_NOT_FOUND
							|| response.getStatusCode() == HttpStatus.SC_NOT_ACCEPTABLE
							|| response.getStatusCode() == HttpStatus.SC_BAD_REQUEST) {
						resultType = ResultType.REQUES_ERROR;
					} else if (response.getStatusCode() == HttpStatus.SC_GATEWAY_TIMEOUT
							|| response.getStatusCode() == HttpStatus.SC_SERVICE_UNAVAILABLE
							|| response.getStatusCode() == HttpStatus.SC_BAD_GATEWAY
							|| response.getStatusCode() == HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED
							|| response.getStatusCode() == HttpStatus.SC_NOT_IMPLEMENTED) {
						resultType = ResultType.SERVER_ERROR;
					}
					Log.d(TAG, "onPostExecute  resultType == " + resultType);
					if (listener != null && listener instanceof Fragment) {
						if (((Fragment) listener).isAdded()) {
							listener.onRequestFinished(resultType, response);
						}
					} else if(listener!=null) {
						listener.onRequestFinished(resultType, response);
					}
				}

				Log.d(TAG, "onPostExecute exit");

			}

			/**
			 * Method 2.
			 */
			if (!isCancelled() && this.handlerReference != null) {

				Handler handler = handlerReference.get();

				if (handler != null) {
					Message message = new Message();
					message.what = CALLBACK_CODE;
					message.obj = response;
					handler.sendMessage(message);
				}

			}
		}
	}
}
